import tkinter as tk  # 导入tkinter模块，用于创建基础GUI组件
from tkinter import ttk  # 导入ttk模块，提供更现代化的控件样式


class CustomNotebook(ttk.Notebook):
    """带有关闭按钮的自定义Notebook控件"""

    def __init__(self, parent, **kwargs):
        # self.isDel = kwargs.pop("isDel")  # 注释掉的代码，原本可能用于接收是否可删除的参数
        # 调用父类ttk.Notebook的初始化方法
        ttk.Notebook.__init__(self, parent, **kwargs)

        # 创建自定义样式对象
        self.style = ttk.Style()

        # 检查是否已创建过close元素，避免重复创建
        try:
            # 尝试获取close元素的选项，如果不存在会抛出异常
            self.style.element_options("close")
        except tk.TclError:
            # 当close元素不存在时，创建关闭按钮的三种状态图像(正常、激活、按下)
            self.images = [
                # 正常状态的关闭按钮图像(使用Base64编码的图像数据)
                tk.PhotoImage("img_close", data='''
                    R0lGODlhCAAIAMIBAAAAADs7O4+Pj9nZ2Ts7Ozs7Ozs7Ozs7OyH+EUNyZWF0ZWQg
                    d2l0aCBHSU1QACH5BAEKAAQALAAAAAAIAAgAAAMVGDBEA0qNJyGw7AmxmuaZhWEU
                    5kEJADs=
                    '''),
                # 鼠标悬停时的关闭按钮图像
                tk.PhotoImage("img_closeactive", data='''
                    R0lGODlhCAAIAMIEAAAAAP/SAP/bNNnZ2Ts7Ozs7Ozs7Ozs7OyH5BAEKAAQALAAAAAAIAAgA
                    AAMVGDBEA0qNJyGw7AmxmuaZhWEU5kEJADs=
                    '''),
                # 按下时的关闭按钮图像
                tk.PhotoImage("img_closepressed", data='''
                    R0lGODlhCAAIAMIEAAAAAOUqKv9mZtnZ2Ts7Ozs7Ozs7Ozs7OyH5BAEKAAQALAAAAAAIAAgA
                    AAMVGDBEA0qNJyGw7AmxmuaZhWEU5kEJADs=
                    ''')
            ]

            # 创建自定义的close元素，设置不同状态下显示的图像
            self.style.element_create("close", "image", "img_close",
                                      # 当按钮被按下且激活且未禁用时，显示按下状态的图像
                                      ("active", "pressed", "!disabled", "img_closepressed"),
                                      # 当按钮激活且未禁用时，显示激活状态的图像
                                      ("active", "!disabled", "img_closeactive"), 
                                      border=8, sticky='')

        # 定义CustomNotebook控件的整体布局
        self.style.layout("CustomNotebook", [("CustomNotebook.client", {"sticky": "nswe"})])
        
        # 定义标签页(Tab)的详细布局，包括标签文本和关闭按钮
        self.style.layout("CustomNotebook.Tab", [
            ("CustomNotebook.tab", {
                "sticky": "nswe",  # 标签页组件向四个方向(北、南、西、东)延伸
                "children": [
                    ("CustomNotebook.padding", {  # 内边距组件
                        "side": "top",  # 位于顶部
                        "sticky": "nswe",
                        "children": [
                            ("CustomNotebook.focus", {  # 焦点组件
                                "side": "top",
                                "sticky": "nswe",
                                "children": [
                                    # 标签文本组件，位于左侧
                                    ("CustomNotebook.label", {"side": "left", "sticky": ''}),
                                    # 关闭按钮组件，位于右侧
                                    ("CustomNotebook.close", {"side": "right", "sticky": ''}),
                                ]
                            })
                        ]
                    })
                ]
            })
        ])

        # 设置标签页的背景色为浅灰色
        self.style.configure("CustomNotebook.Tab", background="#f0f0f0")
        # 设置标签页选中状态时的背景色为白色
        self.style.map("CustomNotebook.Tab", background=[("selected", "#fff")])
        # 设置Notebook控件的背景色为浅灰色
        self.style.configure("CustomNotebook", background="#f0f0f0")

        # 应用自定义样式到当前Notebook控件
        self.configure(style="CustomNotebook")

        # 绑定鼠标按下事件到_on_close_press方法
        self.bind("<ButtonPress-1>", self._on_close_press)
        # 绑定鼠标释放事件到_on_close_release方法
        self.bind("<ButtonRelease-1>", self._on_close_release)

        # 初始化活动状态变量为None
        self._active = None

        # 创建标签页映射字典，用于存储标签页ID和对应的控件
        self.tab_mapping = {}
        # 初始化标签页ID计数器
        self.next_id = 0

    def add(self, child, **kw):
        """重写add方法，保持跟踪标签页ID"""
        # 获取当前可用的标签页ID
        tab_id = self.next_id
        # 将标签页控件与ID关联存储
        self.tab_mapping[tab_id] = child
        # 增加ID计数器，为下一个标签页做准备
        self.next_id += 1
        # 调用父类的add方法添加标签页，并返回结果
        return ttk.Notebook.add(self, child, **kw)

    def forget(self, tab_id):
        """重写forget方法，正确处理标签页移除"""
        # 判断传入的tab_id是否为整数索引
        if isinstance(tab_id, int):
            # 如果是索引，获取所有标签页并找到对应的widget
            tabs = self.tabs()
            if 0 <= tab_id < len(tabs):  # 确保索引在有效范围内
                widget = self.nametowidget(tabs[tab_id])  # 通过索引获取对应的控件
                # 从映射中移除该控件
                for key, value in list(self.tab_mapping.items()):
                    if value == widget:
                        del self.tab_mapping[key]
                        break
        else:
            # 如果传入的是widget或路径名
            for key, value in list(self.tab_mapping.items()):
                if value == tab_id or str(value) == str(tab_id):
                    del self.tab_mapping[key]
                    break

        # 调用原始的forget方法
        return ttk.Notebook.forget(self, tab_id)

    def get_tab_id(self, tab_widget):
        """获取标签页的唯一ID"""
        # 遍历标签页映射字典，查找对应的标签页ID
        for tab_id, widget in self.tab_mapping.items():
            if widget == tab_widget:
                return tab_id
        # 如果未找到匹配的标签页，返回None
        return None

    def _on_close_press(self, event):
        """当按下关闭按钮时"""
        # 识别鼠标点击的元素
        element = self.identify(event.x, event.y)

        # 检查点击的是否为关闭按钮
        if "close" in element:
            # 获取被点击标签页的索引
            index = self.index("@%d,%d" % (event.x, event.y))
            # 设置标签页状态为"pressed"
            self.state(['pressed'])
            # 记录当前活动的标签页索引
            self._active = index
            # 返回"break"以阻止事件进一步传播
            return "break"

    def _on_close_release(self, event):
        """当释放关闭按钮时"""
        # 检查标签页是否处于"pressed"状态
        if not self.instate(['pressed']):
            return

        # 识别鼠标释放的元素
        element = self.identify(event.x, event.y)

        # 如果释放位置不是关闭按钮，直接返回
        if "close" not in element:
            return

        # 获取释放位置对应的标签页索引
        index = self.index("@%d,%d" % (event.x, event.y))

        # 检查是否点击和释放都在同一个有效标签页上
        if self._active == index and index >= 0:
            # 移除该标签页
            self.forget(index)
            # 重置活动标签页状态
            self._active = None
        else:
            # 设置删除标志
            self.isDel = True

        # 重置标签页状态，移除"pressed"状态
        self.state(["!pressed"])

    def get_tabs_info(self):
        """获取所有标签页的信息，用于调试"""
        result = []
        # 遍历所有标签页，收集信息
        for tab_id, widget in self.tab_mapping.items():
            try:
                # 尝试获取标签页的索引和文本
                index = self.index(widget)
                text = self.tab(widget, "text")
                result.append(f"ID: {tab_id}, Widget: {widget}, Index: {index}, Text: {text}")
            except:
                # 如果出现异常（例如标签页已从notebook中移除），记录错误信息
                result.append(f"ID: {tab_id}, Widget: {widget} (not in notebook)")

        return result


class Notebooks(tk.Frame):
    """标签页管理框架类，用于创建和管理标签页界面"""
    def __init__(self, master=None, **kwargs):
        # 从参数中提取isDel参数，用于控制删除功能
        self.isDel = kwargs.get('isDel')

        # 初始化父类Frame
        tk.Frame.__init__(self, master)
        # 保存主窗口引用
        self.root = master

        # 创建自定义Notebook控件实例
        self.notebook = CustomNotebook(self.root,)

        # 将notebook控件放置到父窗口中，设置为填充整个空间
        self.notebook.pack(fill="both", expand=True)

        # 第一个标签页
        self.tab1 = ttk.Frame(self.notebook)
        self.notebook.add(self.tab1, text="数值调节")
        self.start()
        
        # 存储已创建的标签页，避免重复创建
        self.created_tabs = {"数值调节": self.tab1}

    def new_tab(self):
        tab_index = self.notebook.index('end') + 1
        tab_new = ttk.Frame(self.notebook)
        self.notebook.add(tab_new, text=f"按钮新增 {tab_index}")

    def delete_tab(self):
        if self.notebook.index('end') > 0:  # 确保至少有一个标签页
            # 获取要删除的标签页索引
            index_to_delete = self.notebook.index('end') - 1
            # 获取所有标签页
            tabs = self.notebook.tabs()
            if tabs:
                # 获取要删除的标签页控件
                tab_to_delete = self.notebook.nametowidget(tabs[index_to_delete])
                # 从created_tabs字典中移除对应的记录
                for tab_name, tab_widget in list(self.created_tabs.items()):
                    if tab_widget == tab_to_delete:
                        del self.created_tabs[tab_name]
                        break
            # 删除标签页
            self.notebook.forget(index_to_delete)
        if len(self.notebook.tabs()) == 0:
            self.isDel.set(True)  # 使用set方法设置BooleanVar的值



    def show_tabs_info(self):
        info = self.notebook.get_tabs_info()
        print("标签页信息:")
        for line in info:
            print(line)
        print("标签页列表:", self.notebook.tabs())

    def start(self):
        """在第一个标签页中创建并放置控制按钮"""
        # 创建"新增Tab"按钮，点击时调用new_tab方法
        ttk.Button(self.tab1, text="新增Tab", command=self.new_tab).pack(pady=10)
        # 创建"删除Tab"按钮，点击时调用delete_tab方法
        ttk.Button(self.tab1, text="删除Tab", command=self.delete_tab).pack(pady=10)
        # 创建"显示标签页信息"按钮，点击时调用show_tabs_info方法
        ttk.Button(self.tab1, text="显示标签页信息", command=self.show_tabs_info).pack(pady=10)


class Main(tk.Frame):
    """主界面类，管理不同视图的切换"""
    def __init__(self, master, **kwargs):
        # 创建一个布尔变量用于监控是否已删除所有标签页
        self.is_del = tk.BooleanVar()
        # 为is_del变量添加跟踪，当值变化时调用check方法
        self.is_del.trace('w', self.check)
        # 初始化note属性为None，用于存储Notebooks实例
        self.note = None
        # 从参数中提取click_item变量，如果不存在则创建一个默认值为空的StringVar
        self.click_item = kwargs.pop('click_item', tk.StringVar(value=''))

        # 调用父类Frame的初始化方法
        super().__init__(master, **kwargs)
        # 保存主窗口引用
        self.root = master

        # 创建并配置自定义样式
        style = ttk.Style()
        style.configure("Custom.TLabel",  # 定义Custom.TLabel样式
                        background="red",  # 设置背景颜色为红色
                        )

        # 创建两个内部框架，分别用于显示欢迎页面和标签页管理页面
        self.home_frame = ttk.Frame(self, style="Custom.TLabel")
        self.notebook = ttk.Frame(self, style="Custom.TLabel")

        # 为click_item变量添加跟踪，当值变化时调用okk方法
        self.click_item.trace('w', self.okk)
        # 立即调用一次okk方法进行初始设置
        self.okk(None)

    def okk(self, *args):
        """根据click_item的值切换显示不同的界面"""
        if not self.click_item.get():
            # 如果click_item为空，显示欢迎页面
            ttk.Label(self.home_frame, text="右侧区域").pack(pady=10)
            ttk.Label(self.home_frame, text="<UNK>").pack(pady=10)
            # 显示home_frame并隐藏notebook框架
            self.home_frame.pack(fill="both", expand=True)
            self.notebook.pack_forget()
        else:
            # 如果click_item不为空，显示标签页管理界面
            self.home_frame.pack_forget()
            
            # 仅在self.note为空时创建Notebooks实例
            if self.note is None:
                self.note = Notebooks(self.notebook, **{
                    'isDel': self.is_del,
                })
            
            # 获取当前点击的项目名称
            item_name = self.click_item.get()
            # 检查是否已经创建过该标签页，或者标签页是否已被删除
            if not hasattr(self.note, 'created_tabs'):
                # 初始化created_tabs字典（如果不存在）
                self.note.created_tabs = {"数值调节": self.note.tab1}
                
            # 检查标签页是否已存在于notebook中
            tab_exists = False
            for tab_widget in self.note.created_tabs.values():
                try:
                    # 尝试获取标签页的索引，如果不存在会抛出异常
                    self.note.notebook.index(tab_widget)
                    tab_exists = True
                    break
                except tk.TclError:
                    # 标签页不存在，从created_tabs中移除
                    for tab_name, tw in list(self.note.created_tabs.items()):
                        if tw == tab_widget:
                            del self.note.created_tabs[tab_name]
                            break
            
            # 如果标签页不存在，创建新的标签页
            if item_name not in self.note.created_tabs or not tab_exists:
                # 创建新的标签页
                new_tab = ttk.Frame(self.note.notebook)
                self.note.notebook.add(new_tab, text=item_name)
                # 记录已创建的标签页
                self.note.created_tabs[item_name] = new_tab
                # 在新标签页中添加一些基本内容
                ttk.Label(new_tab, text=f"这是{item_name}标签页").pack(pady=20)
            
            # 显示notebook框架
            self.notebook.pack(fill="both", expand=True)

    def check(self, *args):
        """当所有标签页被删除时的处理方法"""
        if self.is_del.get():
            # 先将notebook框架从视图中移除
            # 将notebook框架从视图中移除
            self.notebook.pack_forget()
            # 销毁Notebooks实例
            self.note.destroy()
            # 重置note为None，便于下次打开
            self.note = None
            
            # 彻底销毁self.notebook框架中的所有子组件，避免占用空间
            for child in self.notebook.winfo_children():
                child.destroy()
            # 销毁notebook框架本身
            self.notebook.destroy()
            # 创建一个新的空notebook框架，以便下次使用
            self.notebook = ttk.Frame(self, style="Custom.TLabel")
            # 重置is_del标志为False
            self.is_del.set(False)
            # 删除所有标签页后，显示home_frame欢迎页面
            self.home_frame.pack(fill="both", expand=True)
            # 打印调试信息，提示所有标签页已删除
            print('删完咯~')






if __name__ == '__main__':
    root = tk.Tk()
    root.geometry('500x400')
    Main(root)
    root.mainloop()
